// src/api/request.ts

import axios from "axios";
import { tokenRefresh, isRefresh } from "./tokenRefresh.ts";
import { GET_TOKEN, SaveToken, Logout } from "./utils.ts";
import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
  AxiosError,
} from "axios";
import type { ResponseType } from "@/types/api.type.ts";

// 导出Request类，可以用来自定义传递配置来创建实例
class Request {
  instance: AxiosInstance; // axios 实例
  // 基础配置，url和超时时间
  baseConfig: AxiosRequestConfig = {
    baseURL: import.meta.env.VITE_REQUEST_BASE_URL,
    timeout: import.meta.env.VITE_REQUEST_TIMEOUT,
  };

  constructor(config: AxiosRequestConfig) {
    this.instance = axios.create(Object.assign(this.baseConfig, config));
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 禁用axios缓存
        // config.headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
        // config.headers["Pragma"] = "no-cache";
        // config.headers["Expires"] = "0";
        // 一般会请求拦截里面加token，用于后端的验证
        const token = GET_TOKEN();
        token && (config.headers.Authorization = token);
        return config;
      },
      (err: AxiosError) => {
        // 请求错误，这里可以用全局提示框进行提示
        return Promise.reject(err);
      }
    );
    // 响应拦截器
    this.instance.interceptors.response.use(
      async (res: AxiosResponse) => {
        const { code } = res.data;
        if (code === 0) {
          // 请求成功，拿到返回数据
          SaveToken(res.headers); // 有token就保存token
          return res.data;
        } else if (code === 10 && !isRefresh(res.config)) {
          // token过期时特殊处理，无感刷新
          const isSuccess = await tokenRefresh();
          if (isSuccess) {
            res.config.headers.Authorization = GET_TOKEN();
            const newRes = await this.instance.request(res.config);
            return newRes.data;
          }
        }
        // 处理一些自定义的请求失败的业务状态
        ErrorCode[res.data.code]?.();
        return Promise.reject(res.data);
      },
      (err: AxiosError<ResponseType>) => {
        // 处理http错误，进行全局提示
        const { status = 500 } = err;
        HttpErrorCode[status]?.();
        return Promise.reject(err.response);
      }
    );
  }

  // 定义请求方法
  public request(config: AxiosRequestConfig): Promise<ResponseType> {
    return this.instance.request(config);
  }

  public get<T = any>(
    url: string,
    config?: AxiosRequestConfig & { __hasRefresh?: boolean }
  ): Promise<ResponseType<T>> {
    return this.instance.get(url, config);
  }

  public post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<ResponseType<T>> {
    return this.instance.post(url, data, config);
  }

  public put<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<ResponseType<T>> {
    return this.instance.put(url, data, config);
  }

  public delete<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<ResponseType<T>> {
    return this.instance.delete(url, config);
  }
}

// 默认导出Request实例
export default new Request({});

interface ErrorCodeResponse {
  [key: number]: () => void;
}
const ErrorCode: ErrorCodeResponse = {
  10: () => {
    ElMessage.error("token过期，请重新登录");
    Logout();
  },
  20: () => {
    ElMessage.error("暂无权限");
  },
};
const HttpErrorCode: ErrorCodeResponse = {
  400: () => {
    ElMessage.error("请求参数错误");
  },
  404: () => {
    ElMessage.error("请求资源不存在");
  },
  500: () => {
    ElMessage.error("服务器内部错误");
  },
};
